package com.agileplex.products.acc;

import java.io.IOException;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.File;

import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;

/**
 * Public access point of ACC.
 *
 * @creator Rui Tang
 * @date 2008-06-07
 *
 * @LastChanged
 * @LastChangedBy $LastChangedBy: tangrui@agileplex.com $
 * @LastChangedDate $LastChangedDate: 2008-06-21 17:30:53 +0000 (Sat, 21 Jun 2008) $
 * @LastChangedRevision $LastChangedRevision: 3 $
 */
public class Main {

    private final static String DEFAULT_COMMAND_NAME = "run";

    public static void main(String[] args) {

        // Parse command line options.
        Options opts = defineCommandOptions();
        CommandLineParser parser = new PosixParser();
        CommandLine commandLine = null;
        try {
            commandLine = parser.parse(opts, args);
        } catch (ParseException e) {
            e.printStackTrace();
            showHelp(DEFAULT_COMMAND_NAME, opts);
            System.exit(ErrorCode.PARSE_COMMAND_LINE_FAILED);
        }

        // Show help page.
        if (commandLine.hasOption("h")) {
            showHelp(DEFAULT_COMMAND_NAME, opts);
            System.exit(0);
        }

        // Construct configuration file input stream object.
        InputStream configInputStream = null;
        if (commandLine.hasOption("C")) {
            String configFileName = commandLine.getOptionValue("C");
            File configFile = new File(configFileName);
            if (configFile.exists()) {
                try {
                    configInputStream = new FileInputStream(configFile);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        if (configInputStream == null) {
            configInputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(Constants.DEFAULT_CONFIGURATION_FILE_PATH);
        }

        // Construct configuration object.
        Configuration config = null;
        if (configInputStream != null) {
            try {
                config = new Configuration(configInputStream);
            } catch (ConfigurationException e) {
                e.printStackTrace();
                config = new Configuration();
            } finally {
                try {
                    configInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } else {
            config = new Configuration();
        }

        // Construct STDIN input stream object and open session.
        InputStream stdInputStream = System.in;
        if (commandLine.hasOption("F")) {
            String inputFileName = commandLine.getOptionValue("F");
            File inputFile = new File(inputFileName);
            if (inputFile.exists()) {
                try {
                    stdInputStream = new FileInputStream(inputFile);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        Session session = config.createSession();
        try {
            session.open(stdInputStream, System.out);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(ErrorCode.OPEN_SESSION_FAILED);
        } catch (CommandExecutionException e) {
            e.printStackTrace();
            System.exit(ErrorCode.OPEN_SESSION_FAILED);
        } finally {
            try {
                stdInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static Options defineCommandOptions() {
        Options opts = new Options();
        opts.addOption("F", "file", true, "The input file containing commands.");
        opts.addOption("C", "config-file", true, "The configuration file.");
        opts.addOption("h", "help", false, "Show help page.");
        return opts;
    }

    public static void showHelp(String cmd, Options opts) {
        HelpFormatter formatter = new HelpFormatter();
        formatter.printHelp(cmd, opts);
    }
}
